package cate.game.role.res.achievement;

import cate.common.table.d.GDFunc;
import cate.common.table.d.GDNotice;
import cate.common.table.d.GDProp;
import cate.common.table.fight.skill.row.SkillBaseRow;
import cate.common.table.res.achievement.row.AchievementBaseRow;
import cate.common.table.res.achievement.row.AchievementExpRow;
import cate.common.table.res.achievement.row.AchievementRewardRow;
import cate.common.util.GameResult;
import cate.game.chat.ChatContentParam;
import cate.game.res.MixResAdder;
import cate.game.role.FuncOpenChecker;
import cate.game.role.Role;
import cate.game.role.bag.hero.Hero;
import cate.game.role.res.achievement.msg.AchievementDataResp;
import cate.game.role.res.achievement.msg.AchievementExpSentimentResp;
import cate.game.role.res.achievement.msg.AchievementPushResp;
import cate.game.role.task.TaskGroup;
import cate.game.role.task.TaskItem;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@NoteClass("成就")
public class RoleAchievement extends FuncOpenChecker {
    @NoteField("成就达成记录")
    public List<Integer> achievementLogs;

    @NoteField("成就点奖励领取记录")
    public Map<Integer, Boolean> rewardGot;

    @NoteField("心得数据")
    public Map<Integer, ExperienceInfo> exps;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (achievementLogs == null) {
            achievementLogs = new ArrayList<>();
        }
        if (rewardGot == null) {
            rewardGot = new HashMap<>();
        }
        if (exps == null) {
            exps = new HashMap<>();
        }
    }

    @Override
    public void onEnter() {
        initAchievementTask();
        checkExps();
    }

    private void checkExps() {
        for (ExperienceInfo info : exps.values()) {
            if (info != null && StringUtils.isNotBlank(info.onHeroUid)) {
                Hero hero = role.getBag().hero.getItem(info.onHeroUid);
                if (hero == null || hero.expsOn == null || hero.expsOn.expMap.isEmpty() || !hero.expsOn.expMap.containsValue(info.tid)) {
                    info.onHeroUid = null;
                }
            }
        }
    }

    public boolean checkHeroExps(int tid, String heroUid) {
        return exps.containsKey(tid) && StringUtils.equals(exps.get(tid).onHeroUid, heroUid);
    }

    @Override
    public int getFuncId() {
        return GDFunc.ACHIEVEMENT;
    }

    @Override
    public void onAfterOpen() {

    }

    private void initAchievementTask() {
        List<Integer> rowIds = role.getGame().table.achievement.base.getList().stream().map(e -> e.id).collect(Collectors.toList());
        TaskGroup group = getTaskGroup();
        group.addItemListNoRepeat(rowIds);

        List<AchievementExpRow> expRows = role.getGame().table.achievement.exp.getList();
        for (AchievementExpRow exp : expRows) {
            if (!exps.containsKey(exp.id)) {
                ExperienceInfo expInfo = new ExperienceInfo();
                expInfo.tid = exp.id;
                exps.put(expInfo.tid, expInfo);
            }
        }
        noticeUpdate();
    }

    @Override
    public void checkOpen(){
        if(open || role == null){
            return;
        }
        open = role.getFarm().adventure.allSpecialRewardGot();
        if(open){
            onAfterOpen();
        }
    }

    private AchievementBaseRow getAchievementTaskRow(int taskId) {
        return role.getGame().table.achievement.base.get(taskId);
    }

    public void addAchievementPoint(TaskItem taskItem) {
        AchievementBaseRow row = getAchievementTaskRow(taskItem.tid);
        if (row != null) {
            addToLogs(taskItem.tid);
            role.getGame().rank.achievements.record(role, calcTotalPoint());
            lampAchievementDone(row, taskItem.getTpl().name);
            noticeUpdate();
        }
    }

    private void lampAchievementDone(AchievementBaseRow taskRow, String nameYid) {
        if (taskRow == null || !taskRow.announce) {
            return;
        }
        List<ChatContentParam> params = new ArrayList<>();
        params.add(ChatContentParam.c(role.getBase().name));
        params.add(ChatContentParam.c(GDProp.Quality.getDesc(taskRow.difficulty)));
        params.add(ChatContentParam.c(ChatContentParam.TYPE_LANG_ID, Integer.parseInt(nameYid)));
        role.getGame().notice.lampOnline(role, GDNotice.TextId.ACHIEVEMENT_DONE, params);
    }

    private void lampAchievementExpGet(AchievementExpRow expRow) {
        if (expRow == null || !expRow.announce) {
            return;
        }
        SkillBaseRow skillRow = role.getGame().table.skill.base.get(expRow.skill);
        if (skillRow != null) {
            List<ChatContentParam> params = new ArrayList<>();
            params.add(ChatContentParam.c(role.getBase().name));
            params.add(ChatContentParam.c(skillRow.name));
            role.getGame().notice.lampOnline(role, GDNotice.TextId.ACHIEVEMENT_EXP_GOT, params);
        }
    }

    private void addToLogs(int taskId) {
        achievementLogs.add(0, taskId);
        if (achievementLogs.size() > 10) {
            achievementLogs.remove(achievementLogs.size() - 1);
        }
    }

    @JsonIgnore
    private TaskGroup getTaskGroup() {
        return role.getTask().getGroup(getFuncId());
    }

    public GameResult<Void> sentiment(int tid) {
        GameResult<Void> r = new GameResult<>();
        ExperienceInfo expInfo = getExp(tid);
        if (expInfo == null) {
            return r.fail("无法感悟此心得");
        }
        if (expInfo.active) {
            return r.fail("您已经感悟过该心得了");
        }
        TaskGroup group = role.getTask().getGroup(getFuncId());
        if (group == null) {
            return r.fail("您未激活该功能");
        }
        AchievementExpRow expRow = role.getGame().table.achievement.exp.get(expInfo.tid);
        if (expRow == null) {
            return r.fail("无法感悟此心得");
        }
        if (ListUtils.intersection(expRow.unlockList, group.doneList.stream().map(e -> e.tid).collect(Collectors.toList())).size() != expRow.unlockList.size()) {
            return r.fail("达成所需成就后才可感悟");
        }
        expInfo.active = true;
        role.sendNow(new AchievementExpSentimentResp(tid));
        noticeUpdate();
        lampAchievementExpGet(expRow);
        return r;
    }

    public GameResult<Void> getPointReward(int tid) {
        GameResult<Void> r = new GameResult<>();
        if (rewardGot.containsKey(tid)) {
            return r.fail("您已经领取过该奖励");
        }
        AchievementRewardRow rewardRow = role.getGame().table.achievement.reward.get(tid);
        if (rewardRow == null) {
            return r.fail("奖励不存在");
        }
        if (calcTotalPoint() < rewardRow.point) {
            return r.fail("未达到奖励领取条件");
        }
        rewardGot.put(tid, true);
        new MixResAdder()
                .setSendMailWhenFull(true)
                .setDialogReward(true)
                .setRes(rewardRow.rewardStr)
                .exe(role);
        noticeUpdate();
        return r;
    }

    private int calcTotalPoint() {
        TaskGroup taskGroup = getTaskGroup();
        int totalPoint = 0;
        for (TaskItem item : taskGroup.doneList) {
            AchievementBaseRow baseRow = getAchievementTaskRow(item.tid);
            if (baseRow != null) {
                totalPoint += baseRow.point;
            }
        }
        return totalPoint;
    }

    public ExperienceInfo getExp(int tid) {
        return exps.get(tid);
    }

    public void noticeUpdate() {
        role.sendNow(new AchievementDataResp(this));
    }

    public boolean canGetTaskReward(int taskId) {
        AchievementBaseRow baseRow = getAchievementTaskRow(taskId);
        return baseRow != null && calcTotalPoint() >= baseRow.unlockPoint;
    }

    public void checkPush(int taskId) {
        if (!isOpen()) {
            return;
        }
        AchievementBaseRow baseRow = getAchievementTaskRow(taskId);
        if (baseRow != null && baseRow.push && calcTotalPoint() >= baseRow.unlockPoint) {
            role.sendNow(new AchievementPushResp(taskId));
        }
    }
}
